package cn.com.pc.content.controller;

import cn.com.pc.aaa.Constants;
import cn.com.pc.aaa.model.Identity;
import cn.com.pc.content.annotation.LogRequired;
import cn.com.pc.content.domain.Biz;
import cn.com.pc.content.domain.Site;
import cn.com.pc.content.domain.article.Article;
import cn.com.pc.content.domain.article.ArticleNotFoundException;
import cn.com.pc.content.domain.audit.AuditStatus;
import cn.com.pc.content.domain.content.ContentType;
import cn.com.pc.content.dto.ArticleDTO;
import cn.com.pc.content.dto.ArticleForm;
import cn.com.pc.content.dto.PageResult;
import cn.com.pc.content.dto.Sort;
import cn.com.pc.content.service.ContentService;
import cn.com.pc.content.util.BeanUtils;
import cn.com.pc.content.util.IpUtils;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashSet;

/**
 * 文章 controller
 */
@RestController
@RequestMapping("/articles")
@Slf4j
public class ArticleController {

    @Autowired
    private ContentService contentService;

    @Autowired
    private HttpServletRequest request;

    /**
     * 查询文章列表
     * @param site 站点
     * @param biz 业务
     * @param articleForm 文章查询表单
     * @param sort 排序
     * @return
     */
    @GetMapping
    public PageResult<?> listArticleByForm(@RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, ArticleForm articleForm, Sort sort) {
        articleForm.setSite(site);
        articleForm.setBiz(biz);
        return contentService.listContentByForm(articleForm, sort, ContentType.Article);
    }


    /**
     * 查询文章详情
     * @param site
     * @param biz
     * @param articleId
     * @return
     */
    @GetMapping("/{articleId:\\w+}")
    public ArticleDTO getArticle(@RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @PathVariable("articleId") String articleId) {
        ArticleDTO article = (ArticleDTO) contentService.getContent(articleId, site, biz, ContentType.Article);
        if (article == null) {
            throw new ArticleNotFoundException();
        }
        return article;
    }


    /**
     * 新增文章
     * @param site 站点
     * @param biz 业务
     * @param articleDTO 文章实体
     * @return
     * @throws IOException
     */
    @PostMapping
    @LogRequired(operation = "'新增文章' + #_return")
    public String createArticle(@RequestAttribute(Constants.AAA_IDENTITY) Identity identity, @RequestAttribute("site") Site site, @RequestAttribute("biz") Biz biz, @Validated @RequestBody ArticleDTO articleDTO){
        // 查重
        Article article = (Article) contentService.getContentByReferId(articleDTO.getReferId(), site, biz, ContentType.Article);
        if (article != null) {
            articleDTO.setUpdatedBy(identity.getName());
            articleDTO.setUpdatedAt(LocalDateTime.now());
            articleDTO.setIp(IpUtils.getIp(request));
            article = (Article) contentService.updateContent(articleDTO, article, ContentType.Article);
            return article.getId();
        }

        articleDTO.setSite(site);
        articleDTO.setBiz(biz);
        articleDTO.setCreatedAt(LocalDateTime.now());
        articleDTO.setCreatedBy(identity.getName());
        articleDTO.setUpdatedAt(LocalDateTime.now());
        articleDTO.setUpdatedBy(identity.getName());
        articleDTO.setIp(IpUtils.getIp(request));

        article = new Article();
        article = (Article) contentService.createContent(articleDTO, article, ContentType.Article);
        return article.getId();
    }


    /**
     * 修改文章
     * @param site
     * @param biz
     * @param articleId
     * @param articleDTO
     * @return
     */
    @PutMapping("/{articleId:\\w+}")
    @LogRequired(operation = "'修改文章' + #articleId")
    public Article updateArticle(@RequestAttribute(Constants.AAA_IDENTITY) Identity identity, @RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @PathVariable("articleId") String articleId, @Validated @RequestBody ArticleDTO articleDTO) {
        // 判空
        Article article = (Article) contentService.getContentById(articleId, ContentType.Article);
        if(article == null || article.getSite() != site) {
            throw new ArticleNotFoundException();
        }

        articleDTO.setUpdatedBy(identity.getName());
        articleDTO.setUpdatedAt(LocalDateTime.now());
        articleDTO.setIp(IpUtils.getIp(request));
        try {
            request.setAttribute("operation", "，修改属性" + BeanUtils.comparePropertyIgnore(article, articleDTO, "id", "ip", "auditStatus", "risk", "statData", "createdAt", "createdBy", "updatedAt", "updatedBy", "onShelve", "text"));
        } catch (Exception e) {
            log.warn("文章{}生成修改日志有误", articleId);
            e.printStackTrace();
        }
        return (Article) contentService.updateContent(articleDTO, article, ContentType.Article);
    }


    /**
     * 部分修改文章
     * @param site
     * @param biz
     * @param articleDTO
     * @return
     */
    @PatchMapping
    @LogRequired(operation = "'部分修改文章' + #_return.getId()")
    public Article partialUpdateArticle(@RequestAttribute(Constants.AAA_IDENTITY) Identity identity, @RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @RequestBody ArticleDTO articleDTO) {
        // 判空
        String referId = articleDTO.getReferId();
        String id = articleDTO.getId();
        Article article = null;
        if (StringUtils.hasLength(referId) && biz != null) {
            article = (Article) contentService.getContentByReferId(referId, site, biz, ContentType.Article);
        } else if (StringUtils.hasLength(id)){
            article = (Article) contentService.getContentById(id, ContentType.Article);
        }
        if(article == null) {
            throw new ArticleNotFoundException();
        }

        articleDTO.setUpdatedBy(identity.getName());
        articleDTO.setUpdatedAt(LocalDateTime.now());
        articleDTO.setIp(IpUtils.getIp(request));
        return (Article) contentService.partialUpdateContent(articleDTO, article, ContentType.Article);
    }


    /**
     * 上下架文章
     * @param site
     * @param biz
     * @param articleId
     */
    @PatchMapping("/{articleId:\\w+}")
    @LogRequired(operation = "(#json.get('onShelve').asBoolean() == true ? '上架' : '下架') + '文章' + #articleId")
    public Article shelveArticle(@RequestAttribute(Constants.AAA_IDENTITY) Identity identity, @RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @PathVariable("articleId") String articleId, @RequestBody JsonNode json) {
        if (json.get("onShelve") == null) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "onShelve不能为空");
        }
        boolean onShelve = json.get("onShelve").asBoolean();

        // 判空
        Article article = (Article) contentService.getContentById(articleId, ContentType.Article);
        if(article == null || article.getSite() != site) {
            throw new ArticleNotFoundException();
        }

        if (article.isOnShelve() == onShelve) {
            return article;
        }

        if (onShelve && article.getAuditStatus() != AuditStatus.Publish) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "文章未发布");
        }

        article.setUpdatedBy(identity.getName());
        article.setUpdatedAt(LocalDateTime.now());
        article.setOnShelve(onShelve);
        return (Article) contentService.shelveContent(article, ContentType.Article);
    }


    /**
     * 删除文章
     * @param site
     * @param biz
     * @param articleId
     */
    @DeleteMapping("/{articleId:\\w+}")
    @LogRequired(operation = "'删除文章' + #articleId")
    public void deleteArticle(@RequestAttribute(Constants.AAA_IDENTITY) Identity identity, @RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @PathVariable("articleId") String articleId) {
        // 判空
        Article article = (Article) contentService.getContentById(articleId, ContentType.Article);
        if(article == null || article.getSite() != site) {
            throw new ArticleNotFoundException();
        }

        article.setUpdatedBy(identity.getName());
        article.setUpdatedAt(LocalDateTime.now());
        contentService.deleteContent(article, ContentType.Article);
    }


    /**
     * 文章打标签
     * @param site
     * @param biz
     * @param articleId
     * @param articleDTO
     * @return
     */
    @PutMapping("/{articleId:\\w+}/tags")
    @LogRequired(operation = "'文章打标签' + #articleId")
    public Article updateArticleTag(@RequestAttribute(Constants.AAA_IDENTITY) Identity identity, @RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @PathVariable("articleId") String articleId, @RequestBody ArticleDTO articleDTO) {
        if (CollectionUtils.isEmpty(articleDTO.getTagIds())) {
            articleDTO.setTagIds(new HashSet<>() {});
        }
        // 判空
        Article article = (Article) contentService.getContentById(articleId, ContentType.Article);
        if(article == null || article.getSite() != site) {
            throw new ArticleNotFoundException();
        }

        article.setUpdatedBy(identity.getName());
        article.setUpdatedAt(LocalDateTime.now());
        try {
            request.setAttribute("operation", "，修改属性" + BeanUtils.comparePropertyWith(article, articleDTO, "tagIds"));
        } catch (Exception e) {
            log.warn("文章{}生成修改日志有误", articleId);
            e.printStackTrace();
        }
        return (Article) contentService.updateContentTag(article, articleDTO, ContentType.Article);
    }

}
